#!/dev/null

# Should No longer be used
raise

#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
    Part of Seagull - The Pyhon Pages engine
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    Python Page Compiler -- Main
"""
__author__ = 'Jonathan Slenders <jonathan at slenders dot be>'
__license__ = 'GNU LGPL'

__all__ = ('PageEditor', )

import lexer

from compile_exceptions import CompileException

def check_subtree_safety(tree, allow_python_code=False):
	"""
	returns when a tree consists only of strings.
	When 'allow_python_code' = true, also Python code and embedded objects are
	allowed, but no <%!content %>, <%!meta %>, <%!param %> and other special tags
	are allowed.
	"""
	if allow_python_code:
		safe = ('root', 'xml-comment', 'embedded-object', 'include-path', 'python',
				'python-whitespace', 'single-line-comment', 'python-print-escaped',
				'string', 'specialtag-param-key', 'specialtag-param-value',
				'semi-colon', 'colon')
		# TODO: nested controls *can* have <%!content %>-blocks
	else:
		safe = ('root', 'xml-comment')

	if isinstance(tree, lexer.Token):
		# Root
		if not tree.name in safe:
			raise UnsafeTokenException(tree)

		# Children
		for c in tree.children:
			check_subtree_safety(c, allow_python_code)


def get_specialtag_content_node_name(token):
	"""
	Return the name for something like
	<%!content name="..." %>
	"""
	assert isinstance(token, lexer.Token) and token.name == 'specialtag-content'

	# Find the key/value pair which contain the name of this content block
	for d in range(0, len(token.children)):
		if token.children[d].name == 'specialtag-param-key' and \
			token.children[d].get_string_value() == 'name' and \
			token.children[d+1].name == 'specialtag-param-value':

			# Return the name
			return token.children[d+1].get_string_value()

	# No name has been found
	return None


class PageEditor(object):
	def __init__(self, parse_tree):
		assert isinstance(parse_tree, lexer.Token) and parse_tree.name == 'root'

		self.parse_tree = parse_tree

	@staticmethod
	def create_new():
		return PageEditor(lexer.Token('root'))

	def replace_content(self, blockname, new_content):
		"""
		Delete everything within this content block.
		Return the result in a new tree.
		"""
		assert isinstance(new_content, lexer.Token) and new_content.name == 'root'

		# Create a new tree
		tree = lexer.Token('root')
		
		# Walk through all the children
		copy = True
		for t in self.parse_tree.clone().children:
			# <%!content ... %>
			if isinstance(t, lexer.Token) and t.name == 'specialtag-content':
				tree.children.append(t)

				# decide whether to start/stop copying
				if get_specialtag_content_node_name(t) == blockname:
					copy = False

					# Insert new content
					for c in new_content.clone().children:
						tree.children.append(c)
				else:
					copy = True

			# Copy
			elif copy:
				tree.children.append(t)

		# Save new tree
		self.parse_tree = tree

	def add_content(self, blockname, new_content):
		"""
		Create a new content block and insert the new content.
		"""
		assert isinstance(new_content, lexer.Token) and new_content.name == 'root'
		check_subtree_safety(new_content, allow_python_code=True)

		# Insert <%!content name="blockname" %> token
		specialtag_content = lexer.Token('specialtag-content')
		specialtag_param_key = lexer.Token('specialtag-param-key')
		specialtag_param_key.children.append('name')
		specialtag_param_value = lexer.Token('specialtag-param-value')
		specialtag_param_key.children.append(blockname)
		specialtag_content.children.append(specialtag_param_key)
		specialtag_content.children.append(specialtag_param_value)
		self.parse_tree.append(specialtag_content)

		# Copy nodes
		for t in new_content.clone().children:
			self.parse_tree.append(t)

	def add_text_content(self, blockname, new_content):
		"""
		Creates a new content block and inserts this text
		"""
		assert isinstance(new_content, basestring)

		root = lexer.Token('root')
		root.append(new_content)

		self.add_content(blockname, root)

class UnsafeTokenException(Exception):
	def __init__(self, token):
		Exception.__init__(self, "Found unsafe token at line %s, column %s" % (token.line, token.column))
		self.line = token.line
		self.column = token.column

class UnsafeTextException(Exception):
	def __init__(self, text):
		Exception.__init__(self, "Found unsafe text in this string ('%s')" % text)
